package com.king.wxpay.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.stereotype.Service;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.king.wxpay.model.*;
import com.king.wxpay.service.WxPayService;
import com.king.wxpay.util.SimpleXml;
import com.king.wxpay.util.WxConfig;
import com.king.wxpay.util.WxUtil;

import lombok.extern.log4j.Log4j;

/**
 * 微信支付实现
 * @author taomk
 * @version 1.0
 * @since 15-7-10 下午4:08
 */
@Log4j
@Service
public class WxPayServiceImpl implements WxPayService {

	private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public PrePayRes unifiedOrder(PrePayReq wppb) {
		PrePayRes wr = null;
		try {
			if (wppb != null) {
				wppb.setAppid(WxConfig.APP_ID);
				wppb.setMch_id(WxConfig.MCH_ID);
				wppb.setNonce_str(WxUtil.getRandomStr());
				wppb.setNotify_url(WxConfig.PAY_NOTIFY_URL);
				wppb.setSign(WxUtil.createSign(wppb, WxConfig.API_SECRET));

				String xml = new String(SimpleXml.marshall(wppb));
				String content = WxUtil.postXml(WxConfig.UNIFIED_ORDER_URL, xml);

				if (content != null && !"".equals(content)) {
					wr = SimpleXml.unmarshall(PrePayRes.class, content.getBytes());
				}
			}
		} catch (Exception ex) {
			log.error(ex);
		}

		return wr;
	}

	public PrePayRes unifiedOrderFor3(String openid, String appid, String orderCode, String callBackUrl, String totalFee, String subject, String ip) {
		PrePayRes wr = null;
		try {
			PrePayReq wp = new PrePayReq();
			wp.setAppid(appid);
			wp.setOpenid(openid);
			wp.setOut_trade_no(orderCode);
			BigDecimal total = new BigDecimal(totalFee);
			BigDecimal M = new BigDecimal("100");
			total = total.multiply(M);
			wp.setTotal_fee(total.setScale(0, RoundingMode.HALF_UP).intValue());
			wp.setTrade_type(WxConfig.JSAPI);
			wp.setSpbill_create_ip(ip);
			wp.setBody(subject);
			wp.setMch_id(WxConfig.MCH_ID);
			wp.setNonce_str(WxUtil.getRandomStr());
			wp.setNotify_url(callBackUrl);
			wp.setSign(WxUtil.createSign(wp, WxConfig.API_SECRET));

			String xml = new String(SimpleXml.marshall(wp));
			System.out.println(xml);
			String content = WxUtil.postXml(WxConfig.UNIFIED_ORDER_URL, xml);
			System.out.println(content);
			if (content != null && !"".equals(content)) {

				wr = SimpleXml.unmarshall(PrePayRes.class, content.getBytes());
			}
		} catch (Exception ex) {
			log.error(ex);
		}

		return wr;
	}

	public ApplyRefundRes applyRefund(String appId, String outTradeNo, String outRefundNo, long totalFee, long refundFee) {
		try {
			ApplyRefundReq bean = new ApplyRefundReq();
			bean.setAppid(appId);
			bean.setMch_id(WxConfig.MCH_ID);
			// bean.setSub_mch_id("");
			// bean.setDevice_info("");
			bean.setNonce_str(WxUtil.getRandomStr());
//			bean.setTransaction_id(wxTranId); // wx order id
			bean.setOut_trade_no(outTradeNo);
			bean.setOut_refund_no(outRefundNo); // our system
			// refund id
			bean.setTotal_fee(totalFee);// unit fen
			bean.setRefund_fee(refundFee);
			bean.setOp_user_id(WxConfig.MCH_ID);
			bean.setSign(WxUtil.createSign(bean, WxConfig.API_SECRET));

			byte[] reqBytes = SimpleXml.marshall(bean);
			String xml = new String(reqBytes, "UTF-8");
			byte[] retBytes = WxUtil.postSSLXml(WxConfig.REFUND_URL, xml).getBytes();
			ApplyRefundRes result = SimpleXml.unmarshall(ApplyRefundRes.class, retBytes);
			return result;
		} catch (Exception ex) {
			log.error(ex);
		}
		return null;
	}

	public QueryRefundRes queryRefund(String appId, String outTradeNo, String outRefundNo) {
		QueryRefundReq bean = new QueryRefundReq();
		bean.setAppid(appId);
		bean.setMch_id(WxConfig.MCH_ID);
		bean.setNonce_str(WxUtil.getRandomStr());
//		bean.setTransaction_id(wxTranId);
		bean.setOut_trade_no(outTradeNo);
		bean.setOut_refund_no(outRefundNo);
		// bean.setRefund_id(null);
		bean.setSign(WxUtil.createSign(bean, WxConfig.API_SECRET));

		try {
			byte[] reqBytes = SimpleXml.marshall(bean);
			String xml = new String(reqBytes, "UTF-8");
			byte[] retBytes = WxUtil.postXml(WxConfig.QUERY_REFUND_URL, xml).getBytes();
			QueryRefundRes result = parseRefundQueryResult(retBytes);
			return result;
		} catch (Exception ex) {
			log.error(ex);
		}
		return null;
	}

	private QueryRefundRes parseRefundQueryResult(byte[] bytes) {
		Element root = SimpleXml.domParse(bytes).getDocumentElement();
		QueryRefundRes result = SimpleXml.unmarshall(
				QueryRefundRes.class, root);
		int count = Integer.parseInt(root.getElementsByTagName("refund_count")
				.item(0).getTextContent());
		List<RefundInfo> infoList = new ArrayList<RefundInfo>(count);
		for (int i = 0; i < count; i++) {
			String outRefundNo = getChildValue(root, "out_refund_no_" + i);
			String refundId = getChildValue(root, "refund_id_" + i);
			String refundChannel = getChildValue(root, "refund_channel_" + i);
			String refundFee = getChildValue(root, "refund_fee_" + i);
			String couponRefundFee = getChildValue(root, "coupon_refund_fee_"
					+ i);
			String refundStatus = getChildValue(root, "refund_status_" + i);
			RefundInfo info = new RefundInfo();
			info.setOut_refund_no(outRefundNo);
			info.setRefund_id(refundId);
			info.setRefund_channel(refundChannel);
			info.setRefund_fee(refundFee == null ? null : Long
					.valueOf(refundFee));
			info.setCoupon_refund_fee(couponRefundFee == null ? null : Long
					.valueOf(couponRefundFee));
			info.setRefund_status(refundStatus);
			infoList.add(i, info);
		}
		result.setRefundInfoList(infoList);
		return result;
	}

	private String getChildValue(Element element, String tag) {
		NodeList list = element.getElementsByTagName(tag);
		if (list == null || list.getLength() == 0)
			return null;
		return list.item(0).getTextContent();
	}

	@Override
	public QueryOrderRes queryOrder(String appid, String wxTranId, String order) {
		QueryOrderReq bean = new QueryOrderReq();
		bean.setAppid(appid);
		bean.setMch_id(WxConfig.MCH_ID);
		bean.setNonce_str(WxUtil.getRandomStr());
		bean.setTransaction_id(wxTranId);
		bean.setOut_trade_no(order);
		bean.setSign(WxUtil.createSign(bean, WxConfig.API_SECRET));

		try {
			byte[] reqBytes = SimpleXml.marshall(bean);
			String xml = new String(reqBytes, "UTF-8");
			byte[] retBytes = WxUtil.postSSLXml(WxConfig.QUERY_ORDER_URL, xml).getBytes();
			QueryOrderRes result = SimpleXml.unmarshall(QueryOrderRes.class, retBytes);
			return result;
		} catch (Exception ex) {
			log.error(ex);
		}
		return null;
	}

//	public PrePayRes downloadBill(String appid, String billDate) {
//		try {
//			DownloadBillReq bean = new DownloadBillReq();
//			bean.setAppid(appid);
//			bean.setBill_date(billDate);
//			bean.setBill_type("ALL");
//			bean.setMch_id(WxConfig.MCH_ID);
//			bean.setNonce_str(WxUtil.getRandomStr());
//			bean.setSign(WxUtil.createSign(bean, WxConfig.API_SECRET));
//
//			byte[] reqBytes = SimpleXml.marshall(bean);
//			SimpleHttp http = WxUtil.doConnect(appid, WxConfig.DOWNLOAD_BILL_URL);
//			http.writeBytes(reqBytes);
//			InputStream is = http.getConnection().getInputStream();
//			File dir = new File(WxConfig.DOWNLOAD_DIR);
//			if (!dir.exists())
//				dir.mkdirs();
//			FileChannel fc = FileChannel.open(Paths.get(WxConfig.DOWNLOAD_DIR, billDate),
//					StandardOpenOption.CREATE, StandardOpenOption.WRITE,
//					StandardOpenOption.READ);
//			fc.transferFrom(Channels.newChannel(is), 0, is.available());
//			BufferedReader br = new BufferedReader(Channels.newReader(fc,
//					"UTF-8"));
//			String line = br.readLine();
//			if (line.contains("<xml>")) {
//				fc.position(0);
//				PrePayRes result = SimpleXml.unmarshall(PrePayRes.class,
//						Channels.newInputStream(fc));
//				fc.close();
//				return result;
//			}
//			line = null;
//			Pattern pattern = Pattern.compile(",`");
//			List<DownloadBillRes> wxBillEntries = new ArrayList<DownloadBillRes>();
//			while ((line = br.readLine()) != null) {
//				char startChar = line.charAt(0);
//				if (startChar != '`')
//					break;
//				String[] cols = pattern.split(line);
//				cols[0] = cols[0].substring(1);
//				DownloadBillRes entry = parseDownloadBillEntry(cols);
//				wxBillEntries.add(entry);
//				// Db.update("insert into tablename () values(????????????????????????)",);
//			}
//			PrePayRes result = new PrePayRes();
//			result.setWxBillEntries(wxBillEntries);
//			result.setReturn_code("SUCCESS");
//			return result;
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
//		return null;
//	}


	private Date parseDate(String str) {
		try {
			return dateFormat.parse(str);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

//	private DownloadBillRes parseDownloadBillEntry(String[] cols) {
//		DownloadBillRes entry = new DownloadBillRes();
//		entry.setTranDate(parseDate(cols[0]));
//		entry.setPublics(cols[1]);
//		entry.setMchId(cols[2]);
//		entry.setSubMchId(cols[3]);
//		entry.setDeviceInfo(cols[4]);
//		entry.setWxOrderCode(cols[5]);
//		entry.setQdOrderCode(cols[6]);
//		entry.setUserIdentity(cols[7]);
//		entry.setTranType(cols[8]);
//		entry.setStatus(cols[9]);
//		entry.setPayBank(cols[10]);
//		entry.setCurrency(cols[11]);
//		entry.setTotalAmt(cols[12]);
//		entry.setCouponAmt(cols[13]);
//		entry.setWxRefundId(cols[14]);
//		entry.setQdRefundId(cols[15]);
//		entry.setRefundAmt(cols[16]);
//		entry.setCouponRefundAmt(cols[17]);
//		entry.setRefundType(cols[18]);
//		entry.setRefundStatus(cols[19]);
//		entry.setGoodsName(cols[20]);
//		entry.setMchData(cols[21]);
//		entry.setCharge(cols[22]);
//		entry.setRate(cols[23]);
//		return entry;
//	}

	@Override
	public PrePayRes shortUrl() {
		return null;
	}
}
